using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using OpenTK.Math;
using System.Drawing;
using System.Globalization;

namespace Dogfight2008.Common
{
  public class PlyLoader
  {
    public static ColoredTriangleSoup FromString(string repr)
    {
      string header, data;
      SplitHeaderData(repr, out header, out data);
      int numVertices = FindNumVertices(header);
      int numFaces = FindNumFaces(header);
      ColoredTriangleSoup soup = ComputeSoup(data, numVertices, numFaces);
      return soup;
    }

    private static ColoredTriangleSoup ComputeSoup(string data, int numVertices, int numFaces)
    {
      string[] lines
        = data.Trim().Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
      List<string> filteredList = new List<string>();
      foreach (string line in lines)
        if (line.Trim() != "")
          filteredList.Add(line.Trim());

      // Find vector3's first
      Vector3[] vs = new Vector3[numVertices];
      for (int v = 0; v < vs.Length; v++)
        vs[v] = ParseVector3(filteredList[v]);

      ColoredTriangleSoup soup = new ColoredTriangleSoup();
      for (int f = 0; f < numFaces; f++)
      {
        int i, j, k;
        FindFaceIndices(filteredList[f+numVertices], out i, out j, out k);
        ColoredTriangle tri = new ColoredTriangle(Color.White,
          new Triangle(vs[i], vs[j], vs[k]));
        soup.Add(tri);
      }

      return soup;
    }

    private static void FindFaceIndices(string line, out int i, out int j, out int k)
    {
      string[] indices = line.Split(' ');
      i = int.Parse(indices[1]);
      j = int.Parse(indices[2]);
      k = int.Parse(indices[3]);
    }

    private static float mPerInch = 0.0254f;
    private static Vector3 ParseVector3(string line)
    {
      try
      {
        string[] coords = line.Split(' ');
        float x = float.Parse(coords[0],CultureInfo.InvariantCulture);
        float y = float.Parse(coords[1], CultureInfo.InvariantCulture);
        float z = float.Parse(coords[2], CultureInfo.InvariantCulture);
        return Vector3.Mult(new Vector3(x, y, z), mPerInch);
      }
      catch
      {
        throw new Exception("Could not parse 3 floats from: " + line);
      }
    } 
    
    private static int FindNumFaces(string header)
    {
      Match m = Regex.Match(header, "element face (?<COUNT>\\d+)");
      if(m.Success)
        return int.Parse(m.Groups["COUNT"].Value);
      else
        return 0;
    }

    private static int FindNumVertices(string header)
    {
      Match m = Regex.Match(header, "element vertex (?<COUNT>\\d+)");
      if(m.Success)
        return int.Parse(m.Groups["COUNT"].Value);
      else
        return 0;
    }

    private static void SplitHeaderData(string repr, out string header, out string data)
    {
      string[] result = repr.Split(new string[] { "end_header" }, StringSplitOptions.None);
      header = result[0];
      data = result[1];
    }
  }
}
